#include "compat.h"
#include "pipeline.h"

#include <algorithm>
#include <cstdio>
#include <iostream>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <vector>

namespace cfg
{
namespace
{
// 作用：将 s 中的字符按 JSON 规则转义并直接追加到 out（不含外围引号）。
// 说明：
//  - 常见路径（非控制字符、非 \\ 和 \"）使用 [[likely]] 分支，直接输出；
//  - 控制字符与特殊转义采用 [[unlikely]] 分支，避免热路径开销；
//  - 不构造中间 std::string，降低一次拷贝与分配。
static void
append_escaped_json_string(std::string_view s, std::string & out)
{
    static const char * hex = "0123456789abcdef";
    for (unsigned char ch : s)
    {
        switch (ch)
        {
            case '\\':
                [[unlikely]] out.append("\\\\", 2);
                break;
            case '"':
                [[unlikely]] out.append("\\\"", 2);
                break;
            case '\b':
                [[unlikely]] out.append("\\b", 2);
                break;
            case '\f':
                [[unlikely]] out.append("\\f", 2);
                break;
            case '\n':
                [[unlikely]] out.append("\\n", 2);
                break;
            case '\r':
                [[unlikely]] out.append("\\r", 2);
                break;
            case '\t':
                [[unlikely]] out.append("\\t", 2);
                break;
            default:
                if (ch < 0x20) [[unlikely]]
                {
                    // 采用 \u00XX 十六进制转义
                    out.push_back('\\');
                    out.push_back('u');
                    out.push_back('0');
                    out.push_back('0');
                    out.push_back(hex[(ch >> 4) & 0xF]);
                    out.push_back(hex[ch & 0xF]);
                }
                else [[likely]]
                {
                    out.push_back(static_cast<char>(ch));
                }
        }
    }
}

// 作用：对对象键进行稳定排序并返回 pair(key_view, value_ptr) 的向量，避免复制键字符串。
static std::vector<std::pair<std::string_view, const Value *>>
sorted_key_value_view(const Object & obj)
{
    std::vector<std::pair<std::string_view, const Value *>> kv;
    kv.reserve(obj.props.size());
    // 提取键与值指针
    for (const auto & entry : obj.props)
    {
        kv.emplace_back(entry.first, &entry.second);
    }
    // 仅按键排序
    std::sort(
        kv.begin(), kv.end(), [](const auto & a, const auto & b) { return a.first < b.first; });
    return kv;
}

// 作用：将 Value 递归序列化为 JSON 文本。
// 参数：
//  - v: 要序列化的值
//  - out: 追加输出的目标字符串
//  - pretty: 是否美化
//  - indent_width: 每一级缩进使用的空格数
//  - current_indent: 当前缩进层级（用于递归时传递）
static void
serialize_value_json(
    const Value & v, std::string & out, bool pretty, int indent_width, int current_indent)
{
    auto append_indent = [&](int level) { out.append(static_cast<size_t>(level), ' '); };

    if (std::holds_alternative<std::nullptr_t>(v))
    {
        out.append(std::string_view("null"));
        return;
    }
    if (auto pb = std::get_if<bool>(&v))
    {
        out.append(std::string_view(*pb ? "true" : "false"));
        return;
    }
    if (auto pi = std::get_if<int64_t>(&v))
    {
        // 追加整数值（避免临时字符串）
        std::ostringstream oss;
        oss << *pi;
        out.append(oss.str());
        return;
    }
    if (auto pd = std::get_if<double>(&v))
    {
        std::ostringstream oss;
        oss.setf(std::ios::fmtflags(0), std::ios::floatfield);
        oss << *pd;
        out.append(oss.str());
        return;
    }
    if (auto ps = std::get_if<std::string>(&v))
    {
        out.push_back('"');
        append_escaped_json_string(*ps, out);
        out.push_back('"');
        return;
    }
    if (auto parr = std::get_if<std::shared_ptr<const Array>>(&v))
    {
        if (!*parr)
        {
            out.append(std::string_view("null"));
            return;
        }
        out.push_back('[');
        bool first = true;
        for (const auto & item : (*parr)->items)
        {
            if (first) [[likely]]
            {
                first = false;
            }
            else [[unlikely]]
            {
                out.push_back(',');
            }
            if (pretty)
            {
                out.push_back('\n');
                append_indent(current_indent + indent_width);
            }
            serialize_value_json(item, out, pretty, indent_width, current_indent + indent_width);
        }
        if (pretty && !(*parr)->items.empty())
        {
            out.push_back('\n');
            append_indent(current_indent);
        }
        out.push_back(']');
        return;
    }
    if (auto pobj = std::get_if<std::shared_ptr<const Object>>(&v))
    {
        if (!*pobj)
        {
            out.append(std::string_view("null"));
            return;
        }
        out.push_back('{');
        bool first = true;
        for (const auto & kv : sorted_key_value_view(**pobj))
        {
            if (first) [[likely]]
            {
                first = false;
            }
            else [[unlikely]]
            {
                out.push_back(',');
            }
            if (pretty)
            {
                out.push_back('\n');
                append_indent(current_indent + indent_width);
            }
            // key
            out.push_back('"');
            append_escaped_json_string(kv.first, out);
            out.push_back('"');
            if (pretty)
            {
                out.append(std::string_view(": "));
            }
            else
            {
                out.push_back(':');
            }
            // value
            serialize_value_json(
                *kv.second, out, pretty, indent_width, current_indent + indent_width);
        }
        if (pretty && !(*pobj)->props.empty())
        {
            out.push_back('\n');
            append_indent(current_indent);
        }
        out.push_back('}');
        return;
    }
}

// 记录程序启动时 std::cout 的初始 streambuf，用于判断是否被外部捕获/重定向
static std::streambuf * g_cout_initial_rdbuf = std::cout.rdbuf();

// 判断当前 std::cout 是否已被重定向（例如测试中替换 rdbuf 捕获输出）
static bool
cout_is_redirected()
{
    return std::cout.rdbuf() != g_cout_initial_rdbuf;
}

class SinkStdout : public ISink
{
public:
    // 输出配置对象到标准输出：
    //  - 支持紧凑与美化两种输出风格；
    //  - 默认末尾追加换行（可配置）；
    //  - 当检测到 std::cout 被重定向时，始终使用 iostream 路径以便外部正确捕获。
    bool write(const std::shared_ptr<const Object> & root,
               const PluginOptions & options,
               std::vector<ConfigError> & out_errors) override
    {
        using plugin::PluginOptionsChecker;
        PluginOptionsChecker checker("stdout", options);
        checker.add_spec({"format", false, {"json"}, "output format", std::string("json")});
        checker.add_spec({"pretty", false, {}, "pretty print", std::string("false")});
        checker.add_spec({"indent", false, {}, "indent width", std::string("2")});
        checker.add_spec({"newline", false, {}, "append newline", std::string("true")});

        if (!checker.validate(out_errors))
        {
            return false;
        }

        auto format_opt = checker.get_string("format", std::string("json"));
        auto pretty_opt = checker.get_bool("pretty", false);
        auto indent_opt = checker.get_int64("indent", 2);
        auto newline_opt = checker.get_bool("newline", true);
        if (!format_opt)
            out_errors.push_back(format_opt.error());
        if (!pretty_opt)
            out_errors.push_back(pretty_opt.error());
        if (!indent_opt)
            out_errors.push_back(indent_opt.error());
        if (!newline_opt)
            out_errors.push_back(newline_opt.error());
        if (!pretty_opt || !indent_opt || !newline_opt)
        {
            return false;
        }
        bool pretty = *pretty_opt;
        bool newline = *newline_opt;
        int indent = static_cast<int>(*indent_opt);
        if (indent < 0)
            indent = 2;
        try
        {
            std::string out;
            if (root)
            {
                Value root_v = std::shared_ptr<const Object>(root);
                serialize_value_json(root_v, out, pretty, indent, 0);
            }
            else
            {
                out.assign(std::string_view("null"));
            }

            // 根据可用性与捕获状态选择输出路径：
            //  - 若可用 std::print 且未被捕获，使用更高效的 stdio 路径；
            //  - 否则使用 iostream，保证测试等场景可捕获。
            bool can_use_std_print = false;
#if CFG_HAVE_STD_PRINT
            can_use_std_print = !cout_is_redirected();
#endif

            if (can_use_std_print)
            {
                if (newline)
                    cfg::println(out);
                else
                    cfg::print(out);
            }
            else
            {
                std::cout << out;
                if (newline)
                    std::cout << '\n';
                std::cout.flush();
            }
            return true;
        }
        catch (const std::exception & ex)
        {
            out_errors.push_back(
                ConfigError{Errc::Other, std::string("sink_stdout failed: ") + ex.what(), {}});
            return false;
        }
    }
};

} // namespace

// 注册为 "stdout" sink
REGISTER_SINK("stdout", SinkStdout);

} // namespace cfg